﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

using LowLevelGraphics.Extensions;

using LowLevelGraphics.Filter;

namespace LowLevelGraphics
{
    //TODO: implement fully and Test (All PROCESSING_MODES HAVE TO BE TESTED, PROCESSINGMODE.ColorCount does not work yet
    /// <summary>
    /// 
    /// </summary>
    public class ColorCounter : Dictionary<object, int>
    {
        private UnsafeBitmap m_Bitmap = null;
        protected int m_nMinCount = int.MaxValue;
        protected int m_nMaxCount = -1;
        protected object m_nCurrentObject = null;
        protected ColorCalculation m_Calculation = null;

        protected PROCESSING_MODE M_PROCESSING_MODE = PROCESSING_MODE.ColorCount;

        /// <summary>
        /// Initializes a new instance of the <see cref="ColorCounter"/> class.
        /// </summary>
        /// <param name="_bitmap">The _bitmap.</param>
        /// <param name="_PROCESSINGMODE">The _ PROCESSINGMODE.</param>
        public ColorCounter(UnsafeBitmap _bitmap, PROCESSING_MODE _PROCESSINGMODE)
        {
            m_Bitmap = _bitmap;
            M_PROCESSING_MODE = _PROCESSINGMODE;
            m_Calculation = Definitions.ColorCalculationDictionaryProcessingMode[M_PROCESSING_MODE];
        }

        /// <summary>
        /// Gets or sets the processing mode.
        /// </summary>
        /// <value>The processing mode.</value>
        public PROCESSING_MODE ProcessingMode
        {
            get { return M_PROCESSING_MODE; }
            set { M_PROCESSING_MODE = value; }
        }

        /// <summary>
        /// Gets the max count.
        /// </summary>
        /// <value>The max count.</value>
        public int MaxCount
        {
            get { return m_nMaxCount; }
        }

        /// <summary>
        /// Gets the min count.
        /// </summary>
        /// <value>The min count.</value>
        public int MinCount
        {
            get { return m_nMinCount; }
        }

        /// <summary>
        /// Processes this instance.
        /// </summary>
        public void Process()
        {
            Process(new Rectangle(0, 0, m_Bitmap.Width, m_Bitmap.Height));
        }

        /// <summary>
        /// Processes the specified _rectangle.
        /// </summary>
        /// <param name="_rectangle">The _rectangle.</param>
        public void Process(Rectangle _rectangle)
        {
            int nMinCount = -1;
            int nMaxCount = -1;

            this.Clear();

            int nHeight = m_Bitmap.Height;
            int nWidth = m_Bitmap.Width;

            for (int y = 0; y < nHeight; y++)
            {
                for (int x = 0; x < nWidth; x++)
                {
                    AddValue(m_Calculation(m_Bitmap.GetPixel(x, y)));
                    int nCount = this[m_nCurrentObject];
                    if (nCount > m_nMaxCount) m_nMaxCount = nCount;
                    if (nCount < m_nMinCount) m_nMinCount = nCount;
                }
            }
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <returns></returns>
        public int GetValue(Color _color)
        {
            float fCalculation = m_Calculation(_color);
            if (this.ContainsKey(fCalculation))
            {
                return this[fCalculation];
            }
            else
            {
                return 0;
            }
        }

        /// <summary>
        /// Adds the value.
        /// </summary>
        /// <param name="_Oobject">The _ oobject.</param>
        private void AddValue(object _Oobject)
        {
            if (!this.ContainsKey(_Oobject))
            {
                this.Add(_Oobject, 1);
            }
            else
            {
                this[_Oobject] = this[_Oobject] + 1;
            }
            m_nCurrentObject = _Oobject;
        }
    }
}
